package me.cangming.cmfixsdk;

import android.content.Context;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;

import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;

/**
 * @date 创建时间：2019-09-10
 * @auther cangming
 * @Description 动态修复类
 */
public class Fix {

    //存放需要修复的dex集合
    private static HashSet<File> loadedDex = new HashSet<>();

    static {
        //修复前先清空
        loadedDex.clear();
    }

    public static void init(Context context) {
        File targetFile = new File(context.getDir("odex", Context.MODE_PRIVATE).getAbsolutePath() + File.separator + "hack.jar");
        if (!targetFile.exists()) {
            try {
                FileUtils.copyAssets(context, "hack.jar", targetFile.getAbsolutePath());
                loadFixedDex(context);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            loadFixedDex(context);
        }
    }

    public static void loadFixedDex(Context context) {
        //dex文件目录
        File fileDir = context.getDir("odex", Context.MODE_PRIVATE);
        File[] files = fileDir.listFiles();
        for (File file : files) {
            if (file.getName().endsWith(".jar") && !"classes.dex".equals(file.getName())) {
                //找到要修复的dex文件
                loadedDex.add(file);
            }
        }
        //创建类加载器
        createDexClassLoader(context, fileDir);
    }

    /**
     * 创建类加载器
     *
     * @param context
     * @param fileDir
     */
    private static void createDexClassLoader(Context context, File fileDir) {
        String optimizedDirectory = fileDir.getAbsolutePath() + File.separator + "opt_dex";
        File fOpt = new File(optimizedDirectory);
        if (!fOpt.exists()) {
            fOpt.mkdirs();
        }
        DexClassLoader classLoader;
        for (File dex : loadedDex) {
            //初始化类加载器
            classLoader = new DexClassLoader(dex.getAbsolutePath(), optimizedDirectory, null,
                    context.getClassLoader());
            //热修复
            hotFix(classLoader, context);
        }
    }

    private static void hotFix(DexClassLoader myDexClassLoader, Context context) {

        try {
            //系统的类加载器
            PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();
            // 获取系统当前的 dexElements
            Class<?> cl = Class.forName("dalvik.system.BaseDexClassLoader");
            Object pathList = ReflectUtils.getField(cl, "pathList", pathClassLoader);
            Object sysDexElements = ReflectUtils.getField(pathList.getClass(), "dexElements", pathList);
            // 自己的 ClassLoader 获取 myDexElements
            Object obj = ReflectUtils.getField(cl, "pathList", myDexClassLoader);
            Object myDexElements = ReflectUtils.getField(obj.getClass(), "dexElements", obj);
            // 合并 dexElements
            Object combineElements = ReflectUtils.combineArray(myDexElements, sysDexElements);
            // 反射赋值属性值
            ReflectUtils.setField(pathList.getClass(), "dexElements", pathList, combineElements);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
